package com.hz.pay.center.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.hz.pay.center.exception.BizException;
import com.hz.pay.center.factory.PayFactory;
import com.hz.pay.center.model.MerchantInfo;
import com.hz.pay.center.model.PayChannelInfo;
import com.hz.pay.center.model.PaySerialInfo;
import com.hz.pay.center.utils.AlipayUtils;
import com.pay.common.enums.PayChannelEnum;
import com.pay.common.enums.PayStatusEnum;
import com.pay.common.enums.PayWayEnum;
import com.pay.common.req.PayCloseReq;
import com.pay.common.req.PayQueryReq;
import com.pay.common.resp.NetBankPayRespData;
import com.pay.common.resp.PayCloseData;
import com.pay.common.resp.PayNotifyData;
import com.pay.common.resp.Response;
import com.hz.pay.center.service.IMchInfoService;
import com.hz.pay.center.service.IPayChannelService;
import com.hz.pay.center.service.IPaySerialService;
import com.hz.pay.center.service.IPayService;
import com.hz.pay.center.service.strategy.IStrategyPayService;
import com.pay.common.utils.PayDigestUtil;
import com.pay.common.req.NetBankPayReq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.Date;

/**
 * 支付接口具体实现
 */
@Service
public class PayServiceImpl implements IPayService {


    @Autowired
    private IMchInfoService mchInfoService;

    @Autowired
    private IPayChannelService payChannelService;

    @Autowired
    private IPaySerialService paySerialService;

    @Autowired
    private AlipayUtils alipayUtils;

    private Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);


    @Override
    public Response<NetBankPayRespData> doNetBankPay(NetBankPayReq netBankPayReq) {

        Response<NetBankPayRespData> response = new Response<NetBankPayRespData>();

        String mchId = netBankPayReq.getMchId();

        MerchantInfo merchantInfo = mchInfoService.queryByMchId(mchId);

        if (ObjectUtils.isEmpty(merchantInfo)){
            logger.info("订单号为：{}支付失败，原因：商户不存在",netBankPayReq.getOrderId());
//            throw new BizException("商户状态被禁用");

            return Response.returnFail("商户状态被禁用");
        }

        if (!"0".equals(merchantInfo.getStatus())){
            logger.info("订单号为：{}支付失败，原因：商户状态被禁用",netBankPayReq.getOrderId());
//            throw new BizException("商户状态被禁用");
            return Response.returnFail("商户状态被禁用");

        }

        String reqKey = merchantInfo.getReqKey();
        String singType = netBankPayReq.getSignType();
        String sign = netBankPayReq.getSign();
        String payWay = netBankPayReq.getPayWay();
        String payChannel = netBankPayReq.getPayChannel();

        //3.是否支持支付方式

        PayChannelInfo payChannelInfo = payChannelService.queryByMchIdAndPayWay(mchId,payChannel,payWay);

        if (ObjectUtils.isEmpty(payChannelInfo)){
            logger.info("订单号为：{}支付失败，原因：没有配置该支付方式",netBankPayReq.getMchId());

            return Response.returnFail("没有配置该支付方式");
        }

        if (!"0".equals(payChannelInfo.getStatus())){
            logger.info("订单号为：{}支付失败，原因：支付已经被停用",netBankPayReq.getOrderId());
            return Response.returnFail("支付已经被停用");
        }

        //1. 签名验证。目的数据真实性

        //计算出来的签名值
        String newSign = null;
        try {

            JSONObject data = (JSONObject)JSONObject.toJSON(netBankPayReq);
            newSign = PayDigestUtil.generateSignature(data,reqKey,singType);
            logger.info("订单号：{}请求参数生成对应的签名：{}",netBankPayReq.getOrderId(),newSign);

        } catch (Exception e) {
            logger.error("Exception",e);
            return Response.returnFail("签名认证失败");
        }
        //TODO
        if (!sign.equals(newSign)){
            logger.info("订单号为：{}支付失败，原因：请求非法",netBankPayReq.getOrderId());
            return Response.returnFail("请求非法");
        }

        //4.插入支付流水
        PaySerialInfo paySerialInfo = paySerialService.createPaySerial(netBankPayReq);


        //5.根据支付方式调用对应的支付接口
        //策略模式, 单列模式, 工厂模式, 代理模式
        IStrategyPayService strategyPayService = PayFactory.getPayWay(payWay);

        if (ObjectUtils.isEmpty(strategyPayService)){
            logger.info("订单号：{}支付失败，原因：不支持的支付方式{}",netBankPayReq.getOrderId(),payWay);
            return Response.returnFail("不支持的支付方式");
        }


        NetBankPayRespData netBankPayRespData =  strategyPayService.payment(paySerialInfo);

        //返回参数生成签名值

        String respKey = merchantInfo.getRespKey();

        JSONObject data = (JSONObject)JSONObject.toJSON(netBankPayRespData);

        try {
            String respSign = PayDigestUtil.generateSignature(data,respKey,netBankPayReq.getSignType());
            netBankPayRespData.setSign(respSign);
            netBankPayRespData.setSignType(netBankPayReq.getSignType());

            response.setData(netBankPayRespData);
            return response;
        } catch (Exception e) {
            return Response.returnFail("系统繁忙");
        }


//        if(PayChannelEnum.ALIPAY.getCode().equals(netBankPayReq.getPayChannel())){
//            //走支付宝支付
//
//            if (PayWayEnum.ALIPAY_QRCODE_PAY.getCode().equals(netBankPayReq.getPayWay())){
//
//                // 对接支付宝扫码支付接口,获取二维码地址
//                alipayUtils.alipayQrCodePay();
//
//
//            }else if(PayWayEnum.WECHAT_H5_PAY.equals(netBankPayReq.getPayWay())){
//
//        }
//
//
//        }else if(PayChannelEnum.WECHAT.getCode().equals(netBankPayReq.getPayChannel())){
//
//            wechatUtil.wechatQrCodePay();
//
//
//        }else if (PayChannelEnum.ICBC.getCode().equals(netBankPayReq.getPayChannel())) {
//
//        }

        //6.解析银行返回的数据，封装对象，生成签名 返回


    }

    @Override
    public PayNotifyData queryTrade(PayQueryReq payQueryReq) throws BizException {

        //1.签名验证, 用请求参数再次生成签名，和 请求参数中的sign 进行对比
        String newSign = null;
        try {

            JSONObject data = (JSONObject)JSONObject.toJSON(payQueryReq);
            newSign = PayDigestUtil.generateSignature(data,"test123","MD5");
            logger.info("订单号：{}请求参数生成对应的签名：{}",payQueryReq.getPaySerialNo(),newSign);
        } catch (Exception e) {
            logger.error("Exception",e);
        }

        //2. 查询支付流水号是否存在
        String paySerialNo = payQueryReq.getPaySerialNo();
        PaySerialInfo paySerialInfo = paySerialService.queryByPaySerialNo(paySerialNo);

        //2.1 流水不存在 返回 交易不存在
        if (ObjectUtils.isEmpty(paySerialInfo)){
            //交易不存在
            throw  new BizException("交易不存在");
        }


        //2.2 交易存在，状态是成功和 失败， 如果是 直接返回
        if (PayStatusEnum.PAU_SUCCESS.getCode().equals(paySerialInfo.getPayStatus())
            || PayStatusEnum.PAY_FAIL.getCode().equals(paySerialInfo.getPayStatus()) ){
            //交易成功、失败
            return null;
        }



        //2.3交易存在，状态不是成功和 失败， 需要调用支付公司的查询接口


        String payChannel = paySerialInfo.getPayChannel();
        AlipayTradeQueryResponse alipayTradeQueryResponse = null;

        if (PayChannelEnum.ALIPAY.getCode().equals(payChannel)){
            //调用支付宝的查询接口

            try {
                 alipayTradeQueryResponse =  alipayUtils.alipayTradeQuery(paySerialInfo.getPaySerialNo());
            } catch (AlipayApiException e) {
                logger.error("AlipayApiException",e);
            }


        }else if(PayChannelEnum.WECHAT.getCode().equals(payChannel)){

            //钓用微信支付支付查询接口
        }


        //3. 跟你支付公司返回的结果，更新支付流水表中的状态
        PaySerialInfo record = new PaySerialInfo();
        record.setId(paySerialInfo.getId());
        record.setPayStatus(alipayTradeQueryResponse.getTradeStatus());
        record.setPayDesc(alipayTradeQueryResponse.getSubMsg());
        record.setPaySuccessTime(alipayTradeQueryResponse.getSendPayDate());
        record.setBankRespNo(alipayTradeQueryResponse.getTradeNo());
        paySerialService.updateTrade(record);


        //4.封装返回对象，并生成签名
        PayNotifyData payNotifyData = new PayNotifyData();
        payNotifyData.setOrderId(""); //TODO
        JSONObject object = (JSONObject)JSONObject.toJSON(payNotifyData);
        String sign = null;
        try {
            sign = PayDigestUtil.generateSignature(object,"test123","MD5");
        } catch (Exception e) {
            e.printStackTrace();
        }
        payNotifyData.setSign(sign);
        payNotifyData.setSignType("MD5");
        return payNotifyData;
    }

    @Override
    public PayCloseData tradeClose(PayCloseReq payCloseReq) throws BizException {

        //1.验证签名

        PaySerialInfo paySerialInfo = paySerialService.queryByPaySerialNo(payCloseReq.getPaySerialNo());

        if (ObjectUtils.isEmpty(payCloseReq)){

            throw new BizException("流水号不存在");
        }

        if (PayStatusEnum.PAU_SUCCESS.getCode().equals(paySerialInfo.getPayStatus())
            || PayStatusEnum.PAY_FAIL.getCode().equals(paySerialInfo.getPayStatus()) ){

            throw new BizException("该笔交易状态不能关闭");
        }


        if (PayChannelEnum.ALIPAY.getCode().equals(paySerialInfo.getPayChannel())){

            try {
                AlipayTradeCloseResponse closeResponse = alipayUtils.alipayTradeClose(paySerialInfo.getPaySerialNo(),paySerialInfo.getBankRespNo());

                //解析对象
//
//                if ()

//                ;
//                closeResponse.getMsg()

                if ("10000".equals(closeResponse.getCode())){
                    // 关闭交易

                    PaySerialInfo record = new PaySerialInfo();
                    record.setId(paySerialInfo.getId());

                    record.setPayStatus(PayStatusEnum.PAY_FAIL.getCode());
                    record.setPayDesc("用户主动关闭交易");
                    record.setUpdateTime(new Date());

                    paySerialService.updateTrade(record);

                    //封装对象返回

                    PayCloseData payCloseData = new PayCloseData();

                    String sign = null; //生成签名

                    payCloseData.setSign(sign);

                    payCloseData.setSuccess(true);

                    return payCloseData;

                }else {
                    //关闭失败





                }





            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
        }




        return null;
    }
}
